package cn.wzy.onlyoffice.utils.cos;

import cn.wzy.onlyoffice.config.CosConfig;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.UploadResult;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.MultipleFileUpload;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.TransferManagerConfiguration;
import com.qcloud.cos.transfer.Upload;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//上传操作
public class teanstreUtil {

    /**
     * * 初始化CosClient相关配置， appid、accessKey、secretKey、region * @return
     */
    public static COSClient getCosClient() {
        // 1 初始化用户身份信息（secretId, secretKey）。
        // SECRETID和SECRETKEY请登录访问管理控制台 https://console.cloud.tencent.com/cam/capi 进行查看和管理
        COSCredentials cred = new BasicCOSCredentials(CosConfig.Tencent_secretId, CosConfig.Tencent_secretKey); // 不传APPID也可以，APPID和ACCESSKE已经关联过
        // 2 设置 bucket 的地域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
        // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
        //REGIONID地域
        ClientConfig clientConfig = new ClientConfig(new Region(CosConfig.Tencent_regionId));
        // 这里建议设置使用 https 协议
        // 从 5.6.54 版本开始，默认使用了 https
        clientConfig.setHttpProtocol(HttpProtocol.https);
        //生成cos客户端
        COSClient cosclient = new COSClient(cred, clientConfig);
        return cosclient;
    }

    /**
     * 创建 TransferManager 实例，这个实例用来后续调用高级接口
     * cosClient 初始化实例对象
     **/
    public static TransferManager createTransferManager(COSClient cosClient) {
        // 创建一个 COSClient 实例，这是访问 COS 服务的基础实例。
        // 详细代码参见本页: 简单操作 -> 创建 COSClient
        // 自定义线程池大小，建议在客户端与 COS 网络充足（例如使用腾讯云的 CVM，同地域上传 COS）的情况下，设置成16或32即可，可较充分的利用网络资源
        // 对于使用公网传输且网络带宽质量不高的情况，建议减小该值，避免因网速过慢，造成请求超时。
        ExecutorService threadPool = Executors.newFixedThreadPool(32);

        // 传入一个 threadpool, 若不传入线程池，默认 TransferManager 中会生成一个单线程的线程池。
        TransferManager transferManager = new TransferManager(cosClient, threadPool);

        // 设置高级接口的配置项
        // 分块上传阈值和分块大小分别为 5MB 和 1MB
        TransferManagerConfiguration transferManagerConfiguration = new TransferManagerConfiguration();
        transferManagerConfiguration.setMultipartUploadThreshold(5 * 1024 * 1024);
        transferManagerConfiguration.setMinimumUploadPartSize(1 * 1024 * 1024);
        transferManager.setConfiguration(transferManagerConfiguration);

        return transferManager;
    }

    /**
     * 关闭 TransferManager
     * 在确定不再通过 TransferManager 的实例调用高级接口之后，一定要关闭这个实例，防止资源泄露。
     ***/
    public static void shutdownTransferManager(TransferManager transferManager) {
        // 指定参数为 true, 则同时会关闭 transferManager 内部的 COSClient 实例。
        // 指定参数为 false, 则不会关闭 transferManager 内部的 COSClient 实例。
        transferManager.shutdownNow(Boolean.TRUE);
    }

    /**
     * 文件上传
     * bucketName 桶名称 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
     * File 本地文件路径
     * key 对象键(Key)是对象在存储桶中的唯一标识。
     */
    // 上传对象
    public static Upload upload(String bucketName, String key, String localFilePath) throws CosServiceException, CosClientException, InterruptedException {
        // 使用高级接口必须先保证本进程存在一个 TransferManager 实例，如果没有则创建
        final COSClient cosClient = teanstreUtil.getCosClient();
        // 详细代码参见本页：高级接口 -> 创建 TransferManager
        final TransferManager transferManager = teanstreUtil.createTransferManager(cosClient);
        File localFile = new File(localFilePath);
        //创建对象
        final PutObjectRequest putObjectRequest1 = new PutObjectRequest(bucketName, key, localFile);
        // 高级接口会返回一个异步结果Upload
        // 可同步地调用 waitForUploadResult 方法等待上传完成，成功返回UploadResult, 失败抛出异常
        Upload upload = transferManager.upload(putObjectRequest1);
        UploadResult uploadResult = upload.waitForUploadResult();
// 确定本进程不再使用 transferManager 实例之后，关闭之
// 详细代码参见本页：高级接口 -> 关闭 TransferManager
        teanstreUtil.shutdownTransferManager(transferManager);
        return upload;
    }

    ;

    /***
     * bucketName 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
     * String key上传的文件名称标识 唯一标识
     * 使用流的形式上传
     * */
    // 上传对象
    public static Upload uploads(String bucketName, String key, InputStream inputStream) throws CosServiceException, CosClientException {
        // 使用高级接口必须先保证本进程存在一个 TransferManager 实例，如果没有则创建
        final COSClient cosClient = teanstreUtil.getCosClient();
        // 详细代码参见本页：高级接口 -> 创建 TransferManager
        TransferManager transferManager = createTransferManager(cosClient);

        // 这里创建一个 ByteArrayInputStream 来作为示例，实际中这里应该是您要上传的 InputStream 类型的流


        ObjectMetadata objectMetadata = new ObjectMetadata();
// 上传的流如果能够获取准确的流长度，则推荐一定填写 content-length
// 如果确实没办法获取到，则下面这行可以省略，但同时高级接口也没办法使用分块上传了
        /*    objectMetadata.setContentLength(inputStreamLength);*/

        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, inputStream, objectMetadata);
        Upload upload = null;
        try {
            // 高级接口会返回一个异步结果Upload
            // 可同步地调用 waitForUploadResult 方法等待上传完成，成功返回UploadResult, 失败抛出异常
            upload = transferManager.upload(putObjectRequest);
            UploadResult uploadResult = upload.waitForUploadResult();
        } catch (CosServiceException e) {
            e.printStackTrace();
        } catch (CosClientException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        teanstreUtil.shutdownTransferManager(transferManager);

        return upload;
    }

    ;
//上传本地目录

    /**
     * bucketName // 存储桶的命名格式为 BucketName-APPID，此处填写的存储桶名称必须为此格式
     * virtualDirectoryKeyPrefix // 设置文件上传到 bucket 之后的前缀目录，设置为 “”，表示上传到 bucket 的根目录
     * directory 本地路径 // 要上传的文件夹的绝对路径
     * includeSubdirectories // 是否递归上传目录下的子目录，如果是 true，子目录下的文件也会上传，且cos上会保持目录结构
     */
//TransferManager 实例封装了从本地一个目录来读取文件并且上传到 COS 的功能，这个功能可以在不破坏目录结构的情况下，将文件上传。同时，也可以指定将目录下的文件上传到另一个目录。
    public static MultipleFileUpload uploadDirectory(String bucketName, String virtualDirectoryKeyPrefix,
                                                     File directory, boolean includeSubdirectories) {
        final COSClient cosClient = teanstreUtil.getCosClient();
        TransferManager transferManager = createTransferManager(cosClient);

        MultipleFileUpload upload = null;
        try {
            // 返回一个异步结果Upload, 可同步的调用waitForUploadResult等待upload结束, 成功返回UploadResult, 失败抛出异常.
            upload = transferManager.uploadDirectory(bucketName, virtualDirectoryKeyPrefix, directory, includeSubdirectories);
            // 或者阻塞等待完成
            upload.waitForCompletion();
        } catch (CosServiceException e) {
            e.printStackTrace();
        } catch (CosClientException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        teanstreUtil.shutdownTransferManager(transferManager);
        return upload;
    }

    ;


    public static void main(String[] args) throws InterruptedException, FileNotFoundException {

        teanstreUtil.uploadDirectory("ems-1311510668", "preif", new File("D:\\text"), Boolean.TRUE);
    }


}